/*
   Copyright 2022 cmanlh

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
/**
 * search select box
 * 
 */
import JscConfig from './config.js';
import JscDatabind from './databind.js';
export default class JscSelectSearch extends JscDatabind {
    static get observedAttributes() { return ['required', 'readonly', 'disabled', 'placeholder', 'value', 'jscbind', 'multiple', 'optionwidth', 'withAddBtn', 'inputLatency'] }

    #value;
    #input = undefined;
    #inputSearch = undefined;
    #container = undefined;
    #optionBar = undefined;
    #resetting = undefined;
    #addNewBtn = undefined;
    #optionWidth = undefined;
    #withAddBtn = false;
    #required = false;
    #multiple = false;
    #jscBind = null;
    #cancelHandler = null;
    #inputLatency = 256;
    #originDataCache = new Map();

    constructor() {
        super();
        this.#init();
        this.#render();
    }

    connectedCallback() {
        this.#bindEventForInput();
    }

    disconnectedCallback() {
        if (null != this.#cancelHandler) {
            document.removeEventListener('click', this.#cancelHandler);
        }
    }

    attributeChangedCallback(name, oldValue, newValue) {
        switch (name) {
            case 'value': {
                if (oldValue != newValue) {
                    this.value = newValue;
                }
                break;
            }
            case 'required': {
                if (oldValue != newValue) {
                    if (null == newValue) {
                        this.#required = false;
                    } else {
                        this.#required == newValue;
                    }
                }
                break;
            }
            case 'disabled': {
                if (oldValue != newValue) {
                    if (newValue || '' == newValue) {
                        this.#input.setAttribute('disabled', true);
                    } else {
                        this.#input.removeAttribute('disabled');
                    }
                }
                break;
            }
            case 'jscbind': {
                if (oldValue != newValue) {
                    this.#jscBind = newValue;
                }
                break;
            }
        }
    }

    bindRefresh(bindStamp) {
        if (super.bindRefresh(bindStamp)) {
            if (null != this.bind && null != this.#jscBind) {
                this.#value = this.fetchBindValue(this.#jscBind);
            }
        }
    }

    set value(val) {
        let self = this;
        let oldValue = self.#value;
        if (oldValue == val) {
            return;
        }
        self.#value = val;
        if (self.#multiple) {
            if (null == self.#value) {
                self.#originDataCache.clear();
                self.#input.value = '';
                self.#input.title = self.#input.value;
            } else {
                let lables = '';
                if (0 == self.#originDataCache.size) {
                    self.fetchSpecialItem(self.#value).then(result => {
                        if (result.length > 0) {
                            let newNodes = document.createDocumentFragment();

                            result.forEach((data) => {
                                self.#originDataCache.set(data.value + '', data);

                                lables = lables.concat(',').concat(data.label);

                                let newLi = document.createElement('li');
                                newLi.title = data.label;
                                newLi.textContent = data.label;
                                newLi.setAttribute('optionValue', data.value);
                                newNodes.appendChild(newLi);
                            });

                            let emptyNotifyNode = document.createElement('li');
                            emptyNotifyNode.textContent = '查询结果为空';
                            this.#optionBar.querySelector('.selectSearchOptionList').replaceChildren(emptyNotifyNode);
                            let ul = this.#optionBar.querySelector('.selectSearchOptionSelected');
                            ul.replaceChildren(newNodes);
                        }

                        self.#input.value = lables.replace(',', '');
                        self.#input.title = self.#input.value;
                    });
                } else {
                    let values = self.#value.split(',');
                    values.forEach((val) => {
                        let data = self.#originDataCache.get(val + '');
                        lables = lables.concat(',').concat(data.label);
                    });

                    self.#input.value = lables.replace(',', '');
                    self.#input.title = self.#input.value;
                }
            }
        } else {
            if (null == self.#value) {
                self.#originDataCache.clear();
                self.#input.value = '';
                self.#input.title = self.#input.value;
            } else {
                let data = self.#originDataCache.get(self.#value + '');
                if (null == data) {
                    self.fetchSpecialItem(self.#value).then(result => {
                        self.#originDataCache.clear();
                        if (result.length > 0) {
                            self.#originDataCache.set(self.#value + '', result[0]);

                            self.#input.value = result[0].label;
                            self.#input.title = self.#input.value;
                        }
                    });
                } else {
                    self.#originDataCache.clear();
                    self.#originDataCache.set(self.#value + '', data);

                    self.#input.value = data.label;
                    self.#input.title = self.#input.value;
                }
            }
        }
        this.updateBindValue(this.#jscBind, this.#value);
    }

    get value() {
        return this.#value;
    }

    #init() {
        let multiple = this.getAttribute('multiple');
        if (null == multiple) {
            this.#multiple = false;
        } else {
            this.#multiple = true;
        }

        let required = this.getAttribute('required');
        if (null == required) {
            this.#required = false;
        } else {
            this.#required = true;
        }

        this.#jscBind = this.getAttribute('jscbind');
        this.#optionWidth = this.getAttribute('optionWidth');
        if (this.getAttribute('inputLatency')) {
            this.#inputLatency = this.getAttribute('inputLatency');
        }
    }

    #render() {
        const shadowRoot = this.attachShadow({ mode: 'open' });
        if (this.getAttribute('withAddBtn')) {
            this.#withAddBtn = this.getAttribute('withAddBtn');
        }

        let template = `
        <link rel='stylesheet' type='text/css' href='${JscConfig.cssUrl}'/>
        <input type='text' class='selectSearch selectSearchInit' readonly>
        <div class='selectSearchContainer' style='display:none;'>
           <div class='selectSearchCtrlBar'>
               <input type='text' class='selectSearchSearch' placeholder='请输入筛选关键字'><button type='button' class='selectSearchResetting'>重置</button>`;
        if (this.#withAddBtn) {
            template = template + `<button type='button' class='selectSearchAddNew'>新增</button>`;
        }
        template = template + `
            </div>
            <div class='selectSearchOptionBar'>
                <ul class='selectSearchOptionList'></ul>`;
        if (this.#multiple) {
            template = template + `
                <ul class='selectSearchOptionSelected'></ul>`;
        }
        template = template + `
            </div>
        </div>`;
        shadowRoot.innerHTML = template;

        this.#input = this.shadowRoot.querySelector('.selectSearch');
        this.#container = this.shadowRoot.querySelector('.selectSearchContainer');
        this.#resetting = this.shadowRoot.querySelector('.selectSearchResetting');
        this.#inputSearch = this.shadowRoot.querySelector('.selectSearchSearch');
        if (this.#withAddBtn) {
            this.#addNewBtn = this.shadowRoot.querySelector('.selectSearchAddNew');
        }
        this.#optionBar = this.shadowRoot.querySelector('.selectSearchOptionBar');
        if (this.#multiple) {
            this.#optionBar.classList.add('selectSearchOptionBarFlex');
            this.#optionBar.querySelectorAll('ul').forEach((ul) => {
                ul.classList.add('selectSearchOptionBarUlFlex');
            });
        }

        if (this.getAttribute('placeholder')) {
            this.#input.setAttribute('placeholder', this.getAttribute('placeholder'));
        }

        if (this.getAttribute('disabled')) {
            this.#input.setAttribute('disabled', true);
        }
    }

    #renderOptions(list) {
        let ul = this.#optionBar.querySelector('.selectSearchOptionList');
        if (0 == list.length) {
            let emptyNotifyNode = document.createElement('li');
            emptyNotifyNode.textContent = '查询结果为空';
            ul.replaceChildren(emptyNotifyNode);
            return;
        }

        let lis = ul.querySelectorAll('li');
        if (lis.length >= list.length) {
            const maxIdx = list.length - 1;
            for (let idx = 0; idx < lis.length; idx++) {
                let li = lis[idx];
                if (idx > maxIdx) {
                    li.remove();
                } else {
                    let data = list[idx];
                    li.title = data.label;
                    li.textContent = data.label;
                    li.setAttribute('optionValue', data.value);
                }
            }
        } else {
            for (let idx = 0; idx < lis.length; idx++) {
                let li = lis[idx];
                let data = list[idx];
                li.title = data.label;
                li.textContent = data.label;
                li.setAttribute('optionValue', data.value);
            }

            let newNodes = document.createDocumentFragment();
            for (let idx = lis.length; idx < list.length; idx++) {
                let newLi = document.createElement('li');
                let data = list[idx];
                newLi.title = data.label;
                newLi.textContent = data.label;
                newLi.setAttribute('optionValue', data.value);
                newNodes.appendChild(newLi);
            }
            if (0 == lis.length) {
                ul.replaceChildren(newNodes);
            } else {
                ul.appendChild(newNodes);
            }
        }
    }

    #bindEventForInput() {
        let self = this;
        let inputTimer = null;

        self.#input.addEventListener('click', function (e) {
            if ('block' == self.#container.style.display) {
                self.#container.style.display = 'none';
                self.#input.classList.remove('selectSearchActive');
                self.#input.classList.add('selectSearchInit');

                if (null != inputTimer) {
                    clearTimeout(inputTimer);
                }

                return;
            }
            self.#input.classList.add('selectSearchActive');
            self.#input.classList.remove('selectSearchInit');

            self.#container.style.display = 'block';
            let inputStyle = window.getComputedStyle(self.#input);
            let inputWidth = parseFloat(inputStyle.width) + parseFloat(inputStyle.borderLeftWidth) + parseFloat(inputStyle.borderRightWidth);
            self.#inputSearch.style.width = inputWidth + 'px';
            self.#container.style.top = self.#input.offsetTop + parseFloat(inputStyle.height) + parseFloat(inputStyle.borderTopWidth) + parseFloat(inputStyle.borderBottomWidth) + 1 + 'px';
            self.#container.style.left = self.#input.offsetLeft + 'px';
            self.#inputSearch.focus();
            if (null != self.#optionWidth && self.#optionWidth > 0) {
                if (self.#multiple) {
                    self.#optionBar.style.width = self.#optionWidth * 2 + 'px';
                } else {
                    self.#optionBar.style.width = self.#optionWidth + 'px';
                }
            } else {
                if (self.#multiple) {
                    self.#optionBar.style.width = inputWidth * 2 + 'px';
                }
            }

            if (self.#multiple) {
                self.#inputSearch.value = null;
                let emptyNotifyNode = document.createElement('li');
                emptyNotifyNode.textContent = '查询结果为空';
                self.#optionBar.querySelector('.selectSearchOptionList').replaceChildren(emptyNotifyNode);
            }
        });

        self.#resetting.addEventListener('click', function (e) {
            self.value = null;
            self.#inputSearch.value = null;

            let emptyNotifyNode = document.createElement('li');
            emptyNotifyNode.textContent = '查询结果为空';
            self.#optionBar.querySelector('.selectSearchOptionList').replaceChildren(emptyNotifyNode);

            if (self.#multiple) {
                self.#optionBar.querySelector('.selectSearchOptionSelected').replaceChildren();
            }

            e.stopPropagation();
        });

        if (self.#withAddBtn) {
            self.#addNewBtn.addEventListener('click', function (e) {
                self.#inputSearch.value = null;

                let emptyNotifyNode = document.createElement('li');
                emptyNotifyNode.textContent = '查询结果为空';
                self.#optionBar.querySelector('.selectSearchOptionList').replaceChildren(emptyNotifyNode);

                self.#container.style.display = 'none';
                self.#input.classList.remove('selectSearchActive');
                self.#input.classList.add('selectSearchInit');

                if (null != inputTimer) {
                    clearTimeout(inputTimer);
                }

                e.stopPropagation();

                self.triggerAddNewEvent();
            });
        }

        self.#inputSearch.addEventListener('input', function (e) {
            if (null == inputTimer) {
                inputTimer = setTimeout(function () {
                    self.fetchSearchItems(self.#inputSearch.value).then((list) => {
                        list.forEach(data => {
                            self.#originDataCache.set(data.value + '', data);
                        });
                        self.#renderOptions(list);
                        inputTimer = null;
                    });
                }, self.#inputLatency);
            }

            e.stopPropagation();
        });

        self.#optionBar.addEventListener('click', function (e) {
            if (e.composed) {
                let li = e.composedPath()[0];
                if (self.#multiple) {

                    let optionList = self.#optionBar.querySelector('.selectSearchOptionList');
                    let selectedList = self.#optionBar.querySelector('.selectSearchOptionSelected');

                    if (li.parentNode.classList.contains('selectSearchOptionList')) {
                        if (null != li.getAttribute('optionValue')) {
                            optionList.removeChild(li);
                            selectedList.appendChild(li);
                        }
                    } else if (li.parentNode.classList.contains('selectSearchOptionSelected')) {
                        if (optionList.childElementCount == 1) {
                            if (null == optionList.childNodes[0].getAttribute('optionValue')) {
                                optionList.childNodes[0].remove();
                            }

                        }
                        selectedList.removeChild(li);
                        optionList.appendChild(li);
                    }

                    let values = '';
                    selectedList.querySelectorAll('li').forEach((selectedLi) => {
                        values = values.concat(',').concat(selectedLi.getAttribute('optionValue'));
                    });

                    self.value = values.replace(',', '');
                } else {
                    let val = li.getAttribute('optionValue');
                    if (null != val) {
                        self.value = val;
                    }

                    self.#inputSearch.value = null;
                    self.#optionBar.querySelector('.selectSearchOptionList').replaceChildren();
                    self.#container.style.display = 'none';
                    self.#input.classList.remove('selectSearchActive');
                    self.#input.classList.add('selectSearchInit');
                }
            }

            e.stopPropagation();
        });

        self.#cancelHandler = function (e) {
            if (e.target != self && 'block' == self.#container.style.display) {
                self.#container.style.display = 'none';
                self.#input.classList.remove('selectSearchActive');
                self.#input.classList.add('selectSearchInit');

                if (null != inputTimer) {
                    clearTimeout(inputTimer);
                }

                return;
            }
        };
        document.addEventListener('click', self.#cancelHandler);
    }

    checkValidity() {
        let errMsg = '';
        if (this.#required && (undefined == this.#value || null == this.#value || '' == this.#value)) {
            errMsg = '该字段不能为空';
        }

        this.#input.setCustomValidity(errMsg);
        this.#input.reportValidity();

        if ('' === errMsg) {
            return true;
        } else {
            return false;
        }
    }

    async fetchSpecialItem(val) {
        return [];
    }

    async fetchSearchItems(val) {
        return [];
    }

    triggerAddNewEvent() {

    }
}

if (!customElements.get('jsc-select-search')) {
    window.customElements.define("jsc-select-search", JscSelectSearch);
}